package com.yang.service.impl;

import com.alibaba.fastjson.JSON;
import com.yang.common.Meta;
import com.yang.common.Result;
import com.yang.service.SearchService;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.apache.commons.beanutils.BeanUtils;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class SearchServiceImpl implements SearchService {
    private final String IndexName = "workticket001";
    private final String resultIndex = "hanchuan001";

    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;

    /**
     * 从ES索引中取文档到目标索引中
     * @return
     * @throws IOException
     */
    @Override
    public List<Meta> getAll() throws IOException {
        SearchRequest request = new SearchRequest(IndexName);
//      进行全量查询
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchAllQuery());
//        设置其每次分页查询的条数
        sourceBuilder.size(5000);

        request.source(sourceBuilder);
//        进行数据的在封装
        List<Meta> list = new ArrayList<>();
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        for (SearchHit hit : response.getHits().getHits()) {
            Meta meta = new Meta();
            meta.setId(IndexName + "_" + hit.getId());
            meta.setMessage(hit.getSourceAsString());
            list.add(meta);
        }

//        查询结束将其批量存放在目标索引中
        BulkRequest bulkRequest = new BulkRequest();
        for (int i = 0; i < list.size(); i++) {
            bulkRequest.add(
                    new IndexRequest(resultIndex)
                            .source(JSON.toJSONString(list.get(i)), XContentType.JSON)
            );
        }
        BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(bulkResponse.hasFailures() +"返回false表示批量插入成功！");

        return list;
    }

    /**
     * 根据所给参数进行搜索
     * @param msg
     * @return
     * @throws IOException
     */
    @Override
    public List<Meta> searchAll(String msg) throws IOException {
        SearchRequest request = new SearchRequest(resultIndex);
//      进行搜索
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchQuery("message",msg));
//        sourceBuilder.size(2000);


//        加入到request中
        request.source(sourceBuilder);

        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        List<Meta> list = new ArrayList<>();
        for (SearchHit hit : response.getHits().getHits()) {
            Meta meta = new Meta();
            try {
                BeanUtils.populate(meta,hit.getSourceAsMap());
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }
            list.add(meta);
        }
        return list;
    }

    /**
     * 根据msg关键字进行搜索，并实现分页查询和高亮显示
     * @param msg
     * @param pageNo
     * @param pageSize
     * @return
     * @throws IOException
     */
    @Override
    public Result searchAllHighLight(String msg, int pageNo, int pageSize) throws IOException {
        if(pageNo <= 1){
            pageNo = 1;
        }
        SearchRequest request = new SearchRequest(resultIndex);
//      进行搜索
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        SearchSourceBuilder builder = sourceBuilder.query(QueryBuilders.matchQuery("message", msg));
//        sourceBuilder.size(2000);

//        分页
        sourceBuilder.from(pageNo);
        sourceBuilder.size(pageSize);


//        进行高亮设置
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("message");
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        sourceBuilder.highlighter(highlightBuilder);

//        加入到request中
        request.source(sourceBuilder);

        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        List<Meta> list = new ArrayList<>();
        for (SearchHit hit : response.getHits().getHits()) {
            //----进行高亮字段的替换
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField message = highlightFields.get("message");

            Map<String,Object> sourceAsMap = hit.getSourceAsMap();
            if (message!=null){
                Text[] fragments = message.fragments();
                String n_mess = "";
                for (Text text : fragments) {
                    n_mess += text;
                }
                sourceAsMap.put("message",n_mess);
            }
            //----结束----

            Meta meta = new Meta();
            try {
                BeanUtils.populate(meta,hit.getSourceAsMap());
                int index = hit.getSourceAsString().indexOf(msg);
                if(index != -1){
                    int index2 = hit.getSourceAsString().indexOf(msg,index+1);
                    if(index2!=-1){
                        meta.setTitle(hit.getSourceAsString().substring(index,index2));
                    }else{
                        meta.setTitle(hit.getSourceAsString().substring(index));
                    }
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }
            list.add(meta);
        }
        Result result = new Result();
        result.setList(list);
        result.setTotal(response.getHits().getTotalHits().value);
        System.out.println(result.getTotal()+"总记录数");
        return result;
    }
}
